//  @ Project : GagalPanen
//  @ File Name : grid.cpp
//  @ Date : 3/9/2011
//  @ Author : 
//
//

#include <assert.h>
#include "mapconstants.h"
#include "grid.hpp"
#include "nonenterablecell.hpp"
#include "nonplantablecell.hpp"
#include "plantablecell.hpp"
#include <string>

Grid::Grid(GameInterface* game, std::vector<std::string> map) : game_(game),
    grid_rep_(map.size(), std::vector<Cell* >(map.size()?map[0].size():0, NULL)) {
  for (int i = 0; i < getRow(); ++i) {
    for (int j = 0; j < getColumn(); ++j) {
      if (MapConstants::isPlantableCell(map[i][j])) {
        grid_rep_[i][j] = new PlantableCell(game);
      } else if (MapConstants::isNonPlantableCell(map[i][j])) {
        grid_rep_[i][j] = new NonPlantableCell(game);
      } else if (MapConstants::isNonEnterableCell(map[i][j])) {
        grid_rep_[i][j] = new NonEnterableCell(game);
      }
    }
  }
  checkRep();
}

Grid::Grid(GameInterface* game, std::ifstream& is) : game_(game),
    grid_rep_() {
  int row, col;
  is >> row >> col;
  is.ignore(); // read newline
  
  grid_rep_ = std::vector< std::vector< Cell* > >(row, std::vector< Cell* >(col));

  for (int i = 0; i < row; ++i) {
    for (int j = 0; j < col; ++j) {
      std::string buffer;
      is >> buffer;
      if (buffer == "PLANTABLECELL") {
        grid_rep_[i][j] = new PlantableCell(game, is);
      } else if (buffer == "NONENTERABLECELL") {
        grid_rep_[i][j] = new NonEnterableCell(game, is);
      } else if (buffer == "NONPLANTABLECELL") {
        grid_rep_[i][j] = new NonPlantableCell(game, is);
      } else {
        assert(false);
      }
    }
  }

  
  checkRep();
}

void Grid::save(std::ofstream& os) {
  os << getRow() << " " << getColumn() << std::endl;

  for (int i = 0; i < getRow(); ++i) {
    for (int j = 0; j < getColumn(); ++j) {
      if (grid_rep_[i][j]->isPlantable()) {
        os << "PLANTABLECELL" << std::endl;
        grid_rep_[i][j]->save(os);
      } else if (!grid_rep_[i][j]->isEnterable()) {
        os << "NONENTERABLECELL" << std::endl;
        grid_rep_[i][j]->save(os);
      } else {
        os << "NONPLANTABLECELL" << std::endl;
        grid_rep_[i][j]->save(os);
      }
    }
  }

}

Grid::~Grid() {
  for (int i = 0; i < getRow(); ++i) {
    for (int j = 0; j < getColumn(); ++j) {
      delete grid_rep_[i][j];
    }
  }
}

bool Grid::containsCell(Cell* cell) {
  for (int i = 0; i < getRow(); ++i) {
    for (int j = 0;j < getColumn(); ++j) {
      if (grid_rep_[i][j] == cell) return true;
    }
  }
  return false;
}

Cell* Grid::getCellAt(int x, int y) {
  assert(y >= 0 && y < getRow());
  assert(x >= 0 && x < getColumn());
  return grid_rep_[y][x];
}

Cell* Grid::getCellInFrontOff(Cell* cell, Direction dir) {
  assert(containsCell(cell));
  int y = getY(cell);
  int x = getX(cell);

  y += DirectionNamespace::getDeltaY(dir);
  x += DirectionNamespace::getDeltaX(dir);

  assert(y >= 0 && y < getRow());
  assert(x >= 0 && x < getColumn());
  
  return getCellAt(x, y);
}

int Grid::getColumn() {
  if (getRow() == 0) {
    return 0;
  } else {
    return grid_rep_[0].size();
  }
}

int Grid::getRow() {
  return grid_rep_.size();
}

void Grid::checkRep() {
  for (int i = 0; i < getRow(); ++i) {
    assert((int)grid_rep_[i].size() == getColumn());
    for (int j = 0; j < getColumn(); ++j) {
      assert((int)grid_rep_[i][j] != 0);
    }
  }
}

int Grid::getX(Cell* cell) {
  for (int i = 0; i < getRow(); ++i) {
    for (int j = 0; j < getColumn(); ++j) {
      if (grid_rep_[i][j] == cell) {
        return j;
      }
    }
  }
  // not found
  assert(false);
}
int Grid::getY(Cell* cell) {
  for (int i = 0; i < getRow(); ++i) {
    for (int j = 0; j < getColumn(); ++j) {
      if (grid_rep_[i][j] == cell) {
        return i;
      }
    }
  }
  // not found
  assert(false);
}


void Grid::advanceDay() {
  for (int i = 0; i < getColumn(); ++i) {
    for (int j = 0; j < getRow(); ++j) {
      getCellAt(i, j)->advanceDay();
    }
  }
  return;
}

void Grid::advanceTime() {
  for (int i = 0; i < getColumn(); ++i) {
    for (int j = 0; j < getRow(); ++j) {
      getCellAt(i, j)->advanceTime();
    }
  }
  return;
}

std::vector<ActionType> Grid::getShortestPathBetween(
  Cell* init_cell, Direction init_direction,
  Cell* destination_cell, Direction dest_direction) {
// TODO
  return std::vector<ActionType>();
}

